home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Notes Demo / musbase.c < prev    next >
C/C++ Source or Header  |  1994-11-06  |  8KB  |  306 lines

  1. #include <Values.h>
  2. #include <Memory.h>
  3. #include <Sound.h>
  4.  
  5. #define MAXCHANNELS (4)
  6.  
  7. #define mus_noSynth (0)
  8.  
  9. struct musdata {
  10.     int numchan; /* number of allocated channels */
  11.     SndChannelPtr chan[MAXCHANNELS]; /* the list of allocated channels */
  12. };
  13.  
  14. static struct musdata *mdat = NULL;
  15.  
  16. OSErr musInitialize(void);
  17. void musFinalize(void);
  18. OSErr musAllocChannels(short newnum);
  19. OSErr musPlay(void);
  20. long musAnalyzeSnd(Handle sndHandle, short *retDataType, short *retWaveLength);
  21.  
  22. static pascal void musCallBack(SndChannelPtr chan, SndCommand cmd);
  23.  
  24. /* Initialize the sound package. 
  25.     This just clears out the arrays and sets numchan (the number of allocated
  26.     channels) to zero. */
  27. OSErr musInitialize()
  28. {
  29.     int ix;
  30.     OSErr err;
  31.     
  32.     if (mdat) {
  33.         return 1; /* ### already inited */
  34.     }
  35.     
  36.     mdat = (struct musdata *)NewPtr(sizeof(struct musdata));
  37.     if (!mdat) {
  38.         err = MemError();
  39.         return err;
  40.     }
  41.     
  42.     mdat->numchan = 0;
  43.     for (ix=0; ix<MAXCHANNELS; ix++) {
  44.         mdat->chan[ix] = NULL;
  45.     }
  46.     for (ix=0; ix<MAXCHANNELS; ix++) {
  47.         /* originally, I wanted to pre-allocate the four data blocks which
  48.             store the channel structures. It didn't work. So now I just set
  49.             the pointer to NULL and let SndNewChannel() allocate the memory
  50.             for me. */
  51.         /*mdat->chan[ix] = (SndChannelPtr)NewPtrClear(sizeof(SndChannel));
  52.         if (!mdat->chan[ix]) {
  53.             err = MemError();
  54.             for (ix=0; ix<MAXCHANNELS; ix++) {
  55.                 if (mdat->chan[ix])
  56.                     DisposePtr(mdat->chan[ix]);    
  57.             }
  58.             return err;
  59.         }*/
  60.         mdat->chan[ix] = NULL;
  61.     }
  62.     
  63.     return noErr;
  64. }
  65.  
  66. /* Shut it all down. 
  67.     reduce the number of allocated channels to zero, and free the memory used by
  68.     the package. */
  69. void musFinalize()
  70. {
  71.     if (!mdat) {
  72.         return; /* already not inited */
  73.     }
  74.     
  75.     musAllocChannels(0);
  76.     
  77.     DisposePtr((Ptr)mdat);
  78.     mdat = NULL;
  79. }
  80.  
  81. /* Set the number of allocated channels to newnum, by calling SndNewChannel or
  82.     SndDisposeChannel as appropriate. */
  83. OSErr musAllocChannels(short newnum) 
  84. {
  85.     int ix, sofar;
  86.     OSErr err, suberr;
  87.     
  88.     if (newnum < 0 || newnum > MAXCHANNELS) {
  89.         return 1; /* ### bad number */
  90.     }
  91.     
  92.     if (newnum > mdat->numchan) {
  93.         err = noErr;
  94.         for (ix=mdat->numchan; ix<newnum; ix++) {
  95.             /*printf("ix=%d; snc(%ld)\n", ix, mdat->chan[ix]);*/
  96.             err = SndNewChannel(&(mdat->chan[ix]), sampledSynth, (long)0, (SndCallBackUPP)musCallBack);
  97.             /*printf("err = %d\n", err);*/
  98.             if (err) {
  99.                 sofar = ix;
  100.                 for (ix = sofar-1; ix >= 0; ix--) {
  101.                     SndDisposeChannel(mdat->chan[ix], TRUE);
  102.                 }
  103.                 mdat->numchan = 0;
  104.                 return err;
  105.             }
  106.         }
  107.         mdat->numchan = newnum;
  108.         return err;
  109.     }
  110.     else if (newnum < mdat->numchan) {
  111.         err = noErr;
  112.         for (ix = mdat->numchan-1; ix >= newnum; ix--) {
  113.             suberr = SndDisposeChannel(mdat->chan[ix], TRUE);
  114.             if (suberr)
  115.                 err = suberr;
  116.         }
  117.         mdat->numchan = newnum;
  118.         return err;
  119.     }
  120.     return noErr;
  121. }
  122.  
  123. OSErr musPlay()
  124. {
  125.     OSErr err;
  126.     Handle inst1, inst2, inst3, inst4, song1, song2, song3, song4;
  127.     
  128.     /* allocate 4 channels */
  129.     err = musAllocChannels(4);
  130.     if (err) return err;
  131.     
  132.     inst1 = Get1Resource('snd ', 9000);
  133.     inst2 = Get1Resource('snd ', 9001);
  134.     inst3 = Get1Resource('snd ', 9002);
  135.     inst4 = Get1Resource('snd ', 9003);
  136.     if (!inst1 || !inst2 || !inst3 || !inst4)
  137.         return ResError();
  138.         
  139.     { /* analyze the sound resources and install them in the four channels */
  140.     
  141.         SndCommand cmd;
  142.         long offset;
  143.         short type, len;
  144.         
  145.         offset = musAnalyzeSnd(inst1, &type, &len);
  146.         /* ((*inst)+offset) is the SoundHeader, CmpSoundHeader, or ExtSoundHeader
  147.             (depending on the encode field) */
  148.         if (type != sampledSynth) {
  149.             return 1; /* ### no sound sample in inst */
  150.         }
  151.         if ((((SoundHeaderPtr)((*inst1)+offset))->encode) != stdSH) {
  152.             return 2; /* compressed or extended sound */
  153.         }
  154.         HLock(inst1);
  155.         cmd.cmd = soundCmd;
  156.         cmd.param1 = 0;
  157.         cmd.param2 = (long)((*inst1)+offset);
  158.         err = SndDoImmediate(mdat->chan[0], &cmd);
  159.         
  160.         offset = musAnalyzeSnd(inst2, &type, &len);
  161.         /* ((*inst)+offset) is the SoundHeader, CmpSoundHeader, or ExtSoundHeader
  162.             (depending on the encode field) */
  163.         if (type != sampledSynth) {
  164.             return 1; /* ### no sound sample in inst */
  165.         }
  166.         if ((((SoundHeaderPtr)((*inst3)+offset))->encode) != stdSH) {
  167.             return 2; /* compressed or extended sound */
  168.         }
  169.         HLock(inst2);
  170.         cmd.param2 = (long)((*inst2)+offset);
  171.         err = SndDoImmediate(mdat->chan[1], &cmd);
  172.         offset = musAnalyzeSnd(inst3, &type, &len);
  173.         
  174.         /* ((*inst)+offset) is the SoundHeader, CmpSoundHeader, or ExtSoundHeader
  175.             (depending on the encode field) */
  176.         if (type != sampledSynth) {
  177.             return 1; /* ### no sound sample in inst */
  178.         }
  179.         if ((((SoundHeaderPtr)((*inst3)+offset))->encode) != stdSH) {
  180.             return 2; /* compressed or extended sound */
  181.         }
  182.         HLock(inst3);
  183.         cmd.param2 = (long)((*inst3)+offset);
  184.         err = SndDoImmediate(mdat->chan[2], &cmd);
  185.         offset = musAnalyzeSnd(inst4, &type, &len);
  186.         
  187.         /* ((*inst)+offset) is the SoundHeader, CmpSoundHeader, or ExtSoundHeader
  188.             (depending on the encode field) */
  189.         if (type != sampledSynth) {
  190.             return 1; /* ### no sound sample in inst */
  191.         }
  192.         if ((((SoundHeaderPtr)((*inst4)+offset))->encode) != stdSH) {
  193.             return 2; /* compressed or extended sound */
  194.         }
  195.         HLock(inst4);
  196.         cmd.param2 = (long)((*inst4)+offset);
  197.         err = SndDoImmediate(mdat->chan[3], &cmd);
  198.  
  199.         song1 = Get1Resource('snd ', 9008);
  200.         song2 = Get1Resource('snd ', 9009);
  201.         song3 = Get1Resource('snd ', 9010);
  202.         song4 = Get1Resource('snd ', 9011);
  203.         if (!song1 || !song2 || !song3 || !song4)
  204.             return ResError();
  205.             
  206.         /* play the four songs in the four channels. This does not even attempt
  207.             to synchronize them, which is why it sounds terrible. */
  208.         HLock(song1);
  209.         HLock(song2);
  210.         HLock(song3);
  211.         HLock(song4);
  212.         SndPlay(mdat->chan[3], song4, TRUE);
  213.         SndPlay(mdat->chan[2], song3, TRUE);
  214.         SndPlay(mdat->chan[1], song2, TRUE);
  215.         SndPlay(mdat->chan[0], song1, TRUE);
  216.         HUnlock(song4);
  217.         HUnlock(song3);
  218.         HUnlock(song2);
  219.         HUnlock(song1);
  220.     }
  221.  
  222.     return err;
  223. }
  224.  
  225. /* musAnalyzeSnd: gratefully stolen straight from SoundApp.
  226.     Must be called with a valid, non-purged snd handle (may be unlocked, though.) */
  227. /* the following structures are helpful: */
  228. struct Snd1Header {
  229.     short format, numSynths;
  230. };
  231. typedef struct Snd1Header *Snd1HdrPtr;
  232. typedef struct Snd1Header **Snd1HdrHndl;
  233. struct SynthInfo {
  234.     short synthID;
  235.     long initOption;
  236. };
  237. typedef struct SynthInfo *SynthInfoPtr;
  238. struct Snd2Header {
  239.     short format, refCount;
  240. };
  241. typedef struct Snd2Header *Snd2HdrPtr;
  242. typedef struct Snd2Header **Snd2HdrHndl;
  243.  
  244.  
  245. long musAnalyzeSnd(Handle sndHandle, short *retDataType, short *retWaveLength)
  246. {
  247.     short dataType, waveLength;
  248.     short synths, howManyCmds;
  249.     long retval;
  250.     Ptr cruisePtr;
  251.     
  252.     retval = 0;
  253.     dataType = mus_noSynth;
  254.     waveLength = 0;
  255.     cruisePtr = *sndHandle;
  256.     if (cruisePtr) {
  257.          if (((Snd1HdrPtr)cruisePtr)->format == firstSoundFormat) {
  258.             synths = ((Snd1HdrPtr)cruisePtr)->numSynths;
  259.             cruisePtr += sizeof(struct Snd1Header);
  260.             cruisePtr += (sizeof(struct SynthInfo) * synths);
  261.         }
  262.         else {
  263.             cruisePtr += sizeof(struct Snd2Header);
  264.         }
  265.         howManyCmds = *((short *)cruisePtr);
  266.         cruisePtr += sizeof(howManyCmds);
  267.  
  268.         do {
  269.             switch ((((SndCommand *)cruisePtr)->cmd) & (~dataOffsetFlag)) {
  270.  
  271.                 case soundCmd:
  272.                 case bufferCmd:
  273.                     dataType = sampledSynth;
  274.                     retval = ((SndCommand *)cruisePtr)->param2;
  275.                     howManyCmds = 0;
  276.                     break;
  277.  
  278.                 case waveTableCmd:
  279.                     dataType = waveTableSynth;
  280.                     waveLength = ((SndCommand *)cruisePtr)->param1;
  281.                     retval = ((SndCommand *)cruisePtr)->param2;
  282.                     howManyCmds = 0;
  283.                     break;
  284.  
  285.                 default:
  286.                     cruisePtr += sizeof(SndCommand);
  287.                     howManyCmds -= 1;
  288.                     break;
  289.  
  290.             }
  291.         }
  292.         while (howManyCmds >= 1);
  293.     }
  294.     
  295.     if (retDataType)
  296.         *retDataType = dataType;
  297.     if (retWaveLength)
  298.         *retWaveLength = waveLength;
  299.     return retval;
  300. }
  301.  
  302. static pascal void musCallBack(SndChannelPtr chan, SndCommand cmd)
  303. {
  304.  
  305. }
  306.